package io.github.cchenxi.crpc.core.consumer;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;

import io.github.cchenxi.crpc.core.api.RpcContext;
import io.github.cchenxi.crpc.core.api.RpcRequest;
import io.github.cchenxi.crpc.core.api.RpcResponse;
import io.github.cchenxi.crpc.core.consumer.http.HttpInvoker;
import io.github.cchenxi.crpc.core.consumer.http.OkHttpInvoker;
import io.github.cchenxi.crpc.core.meta.InstanceMeta;
import io.github.cchenxi.crpc.core.utils.MethodUtil;
import io.github.cchenxi.crpc.core.utils.TypeUtil;

/**
 * 消费端的动态代理处理类
 * Date: 2024-03-10
 *
 * @author chenxi
 */
public class RpcInvocationHandler implements InvocationHandler {
    private Class<?> service;
    private List<InstanceMeta> providers;
    private RpcContext context;

    HttpInvoker httpInvoker = new OkHttpInvoker();

    public RpcInvocationHandler(Class<?> service, List<InstanceMeta> providers, RpcContext context) {
        this.service = service;
        this.providers = providers;
        this.context = context;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (MethodUtil.checkLocalMethod(method)) {
            return null;
        }

        RpcRequest rpcRequest = new RpcRequest();
        rpcRequest.setService(service.getCanonicalName());
        rpcRequest.setMethodSign(MethodUtil.methodSign(method));
        rpcRequest.setArgs(args);

        List<InstanceMeta> instances = context.getRouter().route(providers);
        InstanceMeta instance = context.getLoadBalancer().choose(instances);
        System.out.println("loadBalancer.choose(instances), instance=" + instance);
        RpcResponse<?> rpcResponse = httpInvoker.post(rpcRequest, instance.toUrl());

        if (rpcResponse.isStatus()) {
            Object data = rpcResponse.getData();
            return TypeUtil.castMethodResult(method, data);
        } else {
            Exception ex = rpcResponse.getEx();
            throw new RuntimeException(ex);
        }
    }
}
